package com.drakulo.games.ais.ui.component;

import java.util.List;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Polygon;

import com.drakulo.games.ais.core.Colony;
import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.NumberHelper;
import com.drakulo.games.ais.core.Settings;
import com.drakulo.games.ais.core.delayed.HexagonMapAction;
import com.drakulo.games.ais.ui.ImageManager;
import com.drakulo.games.ais.ui.UIHelper;

/**
 * This class represents an hexagon field
 * 
 * @author Drakulo
 * 
 */
public class HexagonMap extends UIComponent {
	/** The number of horizontal hexagons */
	private int width;
	/** The number of vertical hexagons */
	private int height;
	/** The width of an hexagon */
	private int hexagonSize;
	/** Exploration states */
	private boolean[] exploratation;
	/** Graphic elements */
	private Colony[] elements;
	/** The zones */
	private Polygon[] zones;
	/** Initialization flag */
	private boolean inizialited;
	/** Hovered zone */
	private Polygon hoveredZone;
	/** Selecting mode */
	private boolean selectMode;
	/** The selected polygon index */
	private int selectedZone;
	/** Flag to indicate wich type of zones is available for selection */
	private boolean selectableZoneIsDiscovered;

	public HexagonMap(int width, int height, int hexagonSize) {
		this.width = width;
		this.height = height;
		this.hexagonSize = hexagonSize;

		this.setWidth(hexagonSize * this.width);
		int h = (this.height - 1) * (hexagonSize * 3 / 4) + hexagonSize;
		this.setHeight(h);

		this.exploratation = new boolean[width * height];
		this.exploratation[0] = true;
		this.exploratation[1] = true;
		this.exploratation[5] = true;
		this.elements = new Colony[width * height];
		this.zones = new Polygon[width * height];
	}

	@Override
	public void render(Graphics g) throws SlickException {

		final int spadd = 5;
		final int padd = 2 * spadd; // 10
		final int dpadd = 2 * padd; // 20
		UIHelper.drawBox(g, getOX() - padd, getOY() - padd, getWidth() + dpadd,
				getHeight() + dpadd);

		UIHelper.drawDarkBox(g, getOX() - spadd, getOY() - spadd, getWidth()
				+ padd, getHeight() + padd);

		final int wpad = hexagonSize;
		final int hpad = (hexagonSize * 3 / 4);
		int curx = getOX() + 1;
		int cury = getOY();

		int max = this.width * this.height;
		int row = 0;
		int hoveredIndex = -1;
		// Font font = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white,
		// 20);
		for (int i = 0; i < max; i++) {
			if (row % 2 == 1 && i % this.width == 0) {
				continue;
			}
			Polygon p;
			if (!this.inizialited) {
				p = createHexagonAt(curx, cury, this.hexagonSize);
				this.zones[i] = p;
			} else {
				p = this.zones[i];
			}
			if (exploratation[i] == true) {
				g.setColor(Color.gray);
				g.fill(p);
			}
			if (this.elements[i] != null) {
				int x = curx + (this.hexagonSize / 2)
						- (Settings.TILE_SIZE / 2);
				int y = cury + (this.hexagonSize / 2)
						- (Settings.TILE_SIZE / 2);
				ImageManager.getGfx("command_center").draw(x, y);
			}

			if (this.exploratation[i] == true) {
				g.setColor(Color.green);
			} else {
				g.setColor(Color.red);
			}
			g.draw(p);
			// font.drawString(curx + 25, cury + 25, String.valueOf(i));

			curx += wpad;

			if (i % this.width == this.width - 1) {
				// Start a new line
				row++;
				cury += hpad;
				if (row % 2 == 0) {
					curx = getOX() + 1;
				} else {
					curx = getOX() + (this.hexagonSize / 2) + 1;
				}
			}

			if (p.equals(hoveredZone)) {
				hoveredIndex = i;
			}
		}

		if (this.hoveredZone != null && this.selectMode) {
			if (this.exploratation[hoveredIndex] == this.selectableZoneIsDiscovered) {
				g.setColor(Color.green);
				g.draw(this.hoveredZone);
			} else {
				g.setColor(Color.red);
				g.draw(this.hoveredZone);
			}
		}

		// Zones with action in progress
		List<HexagonMapAction> actions = GameData.getHexagonMapActions();
		for (HexagonMapAction a : actions) {
			if (this.equals(a.getMap())) {
				Polygon poly = this.zones[a.getIndex()];
				g.setColor(Color.yellow);
				g.draw(poly);

				int x = (int) (poly.getMinX() + (this.hexagonSize / 2) - (Settings.TILE_SIZE / 2));
				int y = (int) (poly.getMinY() + (this.hexagonSize / 2) - (Settings.TILE_SIZE / 2));
				if(a.isExploration()){
					ImageManager.getGfx("exploration-white").draw(x, y);
				}else{
					ImageManager.getGfx("top_right_expand-white").draw(x, y);
				}
				int progress = a.getProgression();
				int width = NumberHelper.ruleOf3(100, Settings.TILE_SIZE,
						progress);

				g.setColor(Color.white);
				g.drawRect(x - 1, y - 1, Settings.TILE_SIZE + 2, 5);

				g.setColor(Color.red);
				g.fillRect(x, y, width, 4);
			}
		}

		this.inizialited = true;
	}

	@Override
	public void update(Input input) throws SlickException {
		int mx = input.getMouseX();
		int my = input.getMouseY();
		boolean found = false;
		for (int i = 0; i < this.zones.length; i++) {
			Polygon p = this.zones[i];
			if (p != null && p.contains(mx, my)) {
				this.hoveredZone = p;
				found = true;

				if (this.selectMode) {
					if (this.exploratation[i] == this.selectableZoneIsDiscovered) {
						if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)
								&& this.selectMode) {
							// Zone selected
							this.selectedZone = i;
						}
					}

				}
				break;
			}
		}

		if (!found) {
			this.hoveredZone = null;
		}
	}

	private Polygon createHexagonAt(int x, int y, int size) {
		Polygon p = new Polygon();
		final int quarter = size / 4;
		final int midSize = size / 2;
		final int treeQuarter = quarter * 3;

		p.addPoint(x + midSize, y + 0);
		p.addPoint(x + size, y + quarter);
		p.addPoint(x + size, y + treeQuarter);
		p.addPoint(x + midSize, y + size);
		p.addPoint(x + 0, y + treeQuarter);
		p.addPoint(x + 0, y + quarter);

		return p;
	}

	public void addColonyAt(Colony c, int index) {
		this.elements[index] = c;
	}

	public void setSelectingMode(boolean mode, boolean discovered) {
		this.selectMode = mode;
		this.selectedZone = -1;
		this.selectableZoneIsDiscovered = discovered;
	}

	public int getSelectedZone() {
		return this.selectedZone;
	}

	public void explore(int index) {
		this.exploratation[index] = true;
	}
}
